/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.core.windows.toolbars;
import java.io.*;
import java.util.*;
import java.text.*;
import java.awt.Window;
import java.awt.Container;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
import org.openide.util.NbBundle;
import org.openide.NotifyDescriptor;
import org.openide.DialogDescriptor;
import org.openide.TopManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileLock;
import org.openide.awt.JPopupMenuPlus;
import org.openide.awt.Toolbar;
import org.openide.awt.ToolbarPool;
import org.openide.loaders.XMLDataObject;
import org.netbeans.core.windows.WorkspaceImpl;
import org.w3c.dom.*;
/** Toolbar configuration */
public class ToolbarConfiguration extends Object implements ToolbarPool.Configuration, Toolbar.DnDListener {
protected static final String TOOLBAR_DTD = "org/netbeans/core/windows/toolbars/toolbar.dtd"; // NOI18N
protected static final String TOOLBAR_DTD_PUBLIC_ID = "-//Forte for Java//DTD toolbar//EN"; // NOI18N
protected static final String TOOLBAR_DTD_PUBLIC_ID_OLD = "-//NetBeans IDE//DTD toolbar//EN"; // NOI18N
protected static final Class TOOLBAR_PROCESSOR_CLASS = org.netbeans.core.windows.toolbars.ToolbarProcessor.class;
protected static final String TOOLBAR_ICON_BASE = "/org/netbeans/core/windows/toolbars/xmlToolbars"; // NOI18N
protected static final String EXT_XML = "xml"; // NOI18N
protected static final String EXT_XMLINFO = "xmlinfo"; // NOI18N
protected static final int BASIC_HEIGHT_2 = (Toolbar.BASIC_HEIGHT/2) + 2;
protected static final int BASIC_HEIGHT_4 = (Toolbar.BASIC_HEIGHT/4) + 1;
static {
XMLDataObject.registerCatalogEntry (TOOLBAR_DTD_PUBLIC_ID, TOOLBAR_DTD,
ClassLoader.getSystemClassLoader());
XMLDataObject.registerCatalogEntry (TOOLBAR_DTD_PUBLIC_ID_OLD, TOOLBAR_DTD,
ClassLoader.getSystemClassLoader());
}
protected static final String TAG_CONFIG = "Configuration"; // NOI18N
protected static final String TAG_ROW = "Row"; // NOI18N
protected static final String TAG_TOOLBAR = "Toolbar"; // NOI18N
protected static final String ATT_TOOLBAR_NAME = "name"; // NOI18N
protected static final String ATT_TOOLBAR_POSITION = "position"; // NOI18N
protected static final String ATT_TOOLBAR_VISIBLE = "visible"; // NOI18N
/** standard panel for all configurations */
private static ToolbarPanel toolbarPanel = new ToolbarPanel();
private static ToolbarPool toolbarPool;
private Window toolbarPoolWindow;
private ToolbarLayout toolbarLayout = new ToolbarLayout (this);
private static XMLDataObject.Info xmlinfo;
private ToolbarConstraints draggedToolbar;
private WeakHashMap allToolbars;
/**
* @associates ToolbarRow
*/
private Vector toolbarRows;
private String configName;
private int prefWidth;
/**
* @associates Integer
*/
private HashMap invisibleToolbars;
public static final ResourceBundle bundle = NbBundle.getBundle (ToolbarConfiguration.class);
public ToolbarConfiguration (String name) {
allToolbars = new WeakHashMap();
toolbarRows = new Vector();
configName = name;
invisibleToolbars = new HashMap();
draggedToolbar = null;
}
public ToolbarConfiguration (String name, Document doc) {
this (name);
parseDocument (doc);
}
// IO operations
void parseDocument (Document doc) {
Element rE = doc.getDocumentElement();
if (!TAG_CONFIG.equals (rE.getTagName()))
return;
readConfiguration (rE);
checkToolbarRows();
}
//// reading
void readConfiguration (Element conf) {
NodeList nL = conf.getElementsByTagName (TAG_ROW);
toolbarRows = new Vector();
for (int i = 0; i < nL.getLength(); i++) {
Node node = nL.item (i);
readRow ((Element)node);
}
}
void readRow (Element row) {
ToolbarRow tbRow = new ToolbarRow (this);
addRow (tbRow);
NodeList nL = row.getElementsByTagName (TAG_TOOLBAR);
for (int i = 0; i < nL.getLength(); i++) {
Node node = nL.item (i);
addToolbar (tbRow, readToolbar ((Element)node));
}
}
ToolbarConstraints readToolbar (Element tb) {
String name;
String posStr;
String visStr;
Integer pos;
Boolean vis;
name = tb.getAttribute (ATT_TOOLBAR_NAME);
if (name.length() == 0)
return null;
posStr = tb.getAttribute (ATT_TOOLBAR_POSITION);
if (posStr.length() == 0)
pos = null;
else
pos = new Integer (posStr);
visStr = tb.getAttribute (ATT_TOOLBAR_VISIBLE);
if (visStr.length() == 0)
vis = Boolean.TRUE;
else
vis = new Boolean (visStr);
return checkToolbarConstraints (name, pos, vis);
}
//// writting
boolean tryWriteDocument (String cn) throws IOException {
final FileObject tbFO = TopManager.getDefault().getPlaces().folders().toolbars().getPrimaryFile();
final FileSystem tbFS = tbFO.getFileSystem();
FileObject newFO = tbFS.find (tbFO.getName(), cn, EXT_XML);
if (newFO != null) {
NotifyDescriptor replaceD = new NotifyDescriptor.Confirmation
(MessageFormat.format (bundle.getString ("MSG_replaceConfiguration"),
new String [] { cn }),
NotifyDescriptor.OK_CANCEL_OPTION, NotifyDescriptor.WARNING_MESSAGE);
TopManager.getDefault().notify (replaceD);
if (replaceD.getValue() != DialogDescriptor.OK_OPTION) {
return false;
}
}
writeDocument (cn);
return true;
}
public void writeDocument () throws IOException {
writeDocument (configName);
}
private void writeDocument (final String cn) throws IOException {
WritableToolbarConfiguration wtc = new WritableToolbarConfiguration (toolbarRows, invisibleToolbars);
final StringBuffer sb = new StringBuffer ("<?xml version=\"1.0\"?>\n\n"); // NOI18N
sb.append ("<!DOCTYPE ").append (TAG_CONFIG).append (" PUBLIC \""). // NOI18N
append (TOOLBAR_DTD_PUBLIC_ID).append ("\" \"\">\n\n").append (wtc.toString()); // NOI18N
final FileObject tbFO = TopManager.getDefault().getPlaces().folders().toolbars().getPrimaryFile();
final FileSystem tbFS = tbFO.getFileSystem();
tbFS.runAtomicAction (new FileSystem.AtomicAction () {
public void run () throws IOException {
FileLock lock = null;
OutputStream os = null;
FileObject infoFO = tbFS.find (tbFO.getName(), cn, EXT_XMLINFO);
if (infoFO == null)
infoFO = tbFO.createData (cn, EXT_XMLINFO);
try {
lock = infoFO.lock ();
os = infoFO.getOutputStream (lock);
PrintWriter writer = new PrintWriter (os);
getXMLInfo().write (writer);
writer.close();
} finally {
if (os != null)
os.close ();
if (lock != null)
lock.releaseLock ();
}
lock = null;
os = null;
FileObject xmlFO = tbFS.find (tbFO.getName(), cn, EXT_XML);
if (xmlFO == null)
xmlFO = tbFO.createData (cn, EXT_XML);
try {
lock = xmlFO.lock ();
os = xmlFO.getOutputStream (lock);
PrintWriter writer = new PrintWriter (os);
writer.print (sb.toString());
writer.close();
} finally {
if (os != null)
os.close ();
if (lock != null)
lock.releaseLock ();
}
}
});
}
XMLDataObject.Info getXMLInfo () {
if (xmlinfo == null) {
xmlinfo = new XMLDataObject.Info();
xmlinfo.addProcessorClass (TOOLBAR_PROCESSOR_CLASS);
xmlinfo.setIconBase (TOOLBAR_ICON_BASE);
}
return xmlinfo;
}
//
void reflectChanges () {
try {
writeDocument();
} catch (IOException e) { /* ??? */ }
}
void addToolbar (ToolbarRow row, ToolbarConstraints tc) {
if (tc == null)
return;
if (tc.isVisible())
row.addToolbar (tc);
else {
int rI;
if (row == null)
rI = toolbarRows.size();
else
rI = toolbarRows.indexOf (row);
invisibleToolbars.put (tc, new Integer (rI));
}
allToolbars.put (tc.getName(), tc);
}
void removeToolbar (String name) {
ToolbarConstraints tc = (ToolbarConstraints)allToolbars.remove (name);
if (tc.destroy())
checkToolbarRows();
}
void addRow (ToolbarRow row) {
addRow (row, toolbarRows.size());
}
void addRow (ToolbarRow row, int index) {
ToolbarRow prev = null;
ToolbarRow next = null;
try {
prev = (ToolbarRow)toolbarRows.elementAt (index - 1);
} catch (ArrayIndexOutOfBoundsException e) { }
try {
next = (ToolbarRow)toolbarRows.elementAt (index);
} catch (ArrayIndexOutOfBoundsException e) { }
if (prev != null)
prev.setNextRow (row);
row.setPrevRow (prev);
row.setNextRow (next);
if (next != null)
next.setPrevRow (row);
toolbarRows.insertElementAt (row, index);
updateBounds (row);
}
void removeRow (ToolbarRow row) {
ToolbarRow prev = row.getPrevRow();
ToolbarRow next = row.getNextRow();
if (prev != null) {
prev.setNextRow (next);
}
if (next != null) {
next.setPrevRow (prev);
}
toolbarRows.removeElement (row);
updateBounds (next);
revalidateWindow();
}
void updateBounds (ToolbarRow row) {
while (row != null) {
row.updateBounds();
row = row.getNextRow();
}
}
void revalidateWindow () {
if (toolbarPool == null)
updateToolbarPool();
toolbarPanel.revalidate();
java.awt.Window w = javax.swing.SwingUtilities.windowForComponent (toolbarPool);
if (w != null) {
w.validate ();
}
}
int rowIndex (ToolbarRow row) {
return toolbarRows.indexOf (row);
}
void updatePrefWidth () {
Iterator it = toolbarRows.iterator();
prefWidth = 0;
int tryPrefWidth;
while (it.hasNext()) {
prefWidth = Math.max (prefWidth, ((ToolbarRow)it.next()).getPrefWidth());
}
}
int getPrefWidth () {
return prefWidth;
}
int getPrefHeight () {
double rowCount = getRowCount();
if (rowCount == 0)
rowCount = 0.25;
return (ToolbarLayout.VGAP + (int)((ToolbarLayout.VGAP + Toolbar.BASIC_HEIGHT) * rowCount));
}
void checkToolbarRows () {
Object[] rows = toolbarRows.toArray();
ToolbarRow row;
for (int i = rows.length - 1; i >= 0; i--) {
row = (ToolbarRow)rows[i];
if (row.isEmpty())
removeRow (row);
}
}
int getRowCount () {
return toolbarRows.size();
}
ToolbarConstraints checkToolbarConstraints (String name, Integer position, Boolean visible) {
ToolbarConstraints tc = (ToolbarConstraints)allToolbars.get (name);
if (tc == null)
tc = new ToolbarConstraints (this, name, position, visible);
else
tc.checkNextPosition (position, visible);
return tc;
}
void checkConfigurationOver () {
Object[] names = allToolbars.keySet().toArray();
String name;
for (int i = 0; i < names.length; i++) {
name = (String)names[i];
if (toolbarPool.findToolbar (name) == null)
removeToolbar (name);
}
}
void removeVisible (ToolbarConstraints tc) {
invisibleToolbars.put (tc, new Integer (tc.rowIndex()));
if (tc.destroy())
checkToolbarRows();
tc.setVisible (false);
reflectChanges();
}
void addInvisible (ToolbarConstraints tc) {
int rC = toolbarRows.size();
int pos = ((Integer)invisibleToolbars.remove (tc)).intValue();
tc.setVisible (true);
for (int i = pos; i < pos + tc.getRowCount(); i++) {
getRow (i).addToolbar (tc, tc.getPosition());
}
if (rC != toolbarRows.size())
revalidateWindow();
reflectChanges();
}
ToolbarRow getRow (int rI) {
ToolbarRow row;
int s = toolbarRows.size();
if (rI < 0) {
row = new ToolbarRow (this);
addRow (row, 0);
} else if (rI >= s) {
row = new ToolbarRow (this);
addRow (row);
} else {
row = (ToolbarRow)toolbarRows.elementAt (rI);
}
return row;
}
ToolbarRow createLastRow () {
return getRow (toolbarRows.size());
}
void reactivatePanel () {
toolbarPanel.removeAll();
prefWidth = 0;
Toolbar tbs[] = toolbarPool.getToolbars();
Toolbar tb;
ToolbarConstraints tc;
String name;
for (int i = 0; i < tbs.length; i++) {
tb = tbs[i];
name = tb.getName();
tc = (ToolbarConstraints)allToolbars.get (name);
if (tc == null) {
tc = new ToolbarConstraints (this, name, null, Boolean.FALSE);
addToolbar (null, tc);
}
toolbarPanel.add (tb, tc);
}
}
void updateToolbarPool () {
if (toolbarPoolWindow == null) {
toolbarPool = ToolbarPool.getDefault();
toolbarPoolWindow = javax.swing.SwingUtilities.windowForComponent (toolbarPool);
}
}
// from ToolbarPool.Configuration
/** Activates the configuration and returns right
* component that can display the configuration.
* @return representation component
*/
public Component activate () {
if (toolbarPool == null)
updateToolbarPool();
toolbarPool.setToolbarsListener (this);
checkConfigurationOver();
toolbarPanel.setLayout (toolbarLayout);
reactivatePanel();
return toolbarPanel;
}
/** Name of the configuration.
* @return the name
*/
public String getName () {
return configName;
}
/** Popup menu that should be displayed when the users presses
* right mouse button on the panel. This menu can contain
* contains list of possible configurations, additional actions, etc.
*
* @return popup menu to be displayed
*/
public JPopupMenu getContextMenu () {
JPopupMenu menu = new JPopupMenuPlus ();
// generate list of available toolbars
Iterator it = Arrays.asList (ToolbarPool.getDefault ().getToolbars ()).iterator ();
while (it.hasNext()) {
final Toolbar tb = (Toolbar)it.next();
String name = tb.getName();
final ToolbarConstraints tc = (ToolbarConstraints)allToolbars.get (name);
JCheckBoxMenuItem mi = new JCheckBoxMenuItem (name, tc.isVisible());
mi.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent ae) {
boolean wasVisible = tc.isVisible();
if (wasVisible) {
removeVisible (tc);
tb.setVisible (false);
} else {
addInvisible (tc);
tb.setVisible (true);
}
}
});
menu.add (mi);
}
menu.add (new JPopupMenu.Separator());
// generate list of available toolbar panels
it = Arrays.asList (ToolbarPool.getDefault ().getConfigurations ()).iterator ();
ButtonGroup bg = new ButtonGroup ();
String current = ToolbarPool.getDefault ().getConfiguration ();
while (it.hasNext()) {
final String name = (String)it.next ();
JRadioButtonMenuItem mi = new JRadioButtonMenuItem (name, (name.compareTo (current) == 0));
mi.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent e) {
WorkspaceImpl curWs = (WorkspaceImpl)TopManager.getDefault().
getWindowManager().getCurrentWorkspace();
curWs.setToolbarConfigName (name);
}
});
bg.add (mi);
menu.add (mi);
}
menu.add (new JPopupMenu.Separator());
JMenuItem mi = new JMenuItem (bundle.getString ("PROP_saveAs"));
mi.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent e) {
NotifyDescriptor.InputLine il = new NotifyDescriptor.InputLine
(bundle.getString ("PROP_saveLabel"),
bundle.getString ("PROP_saveDialog"));
il.setInputText (bundle.getString ("PROP_saveName"));
Object ok = TopManager.getDefault ().notify (il);
if (ok == NotifyDescriptor.OK_OPTION) {
String s = il.getInputText();
if (s.length() != 0) {
try {
String newName = il.getInputText();
if (tryWriteDocument (newName)) {
WorkspaceImpl curWs = (WorkspaceImpl)TopManager.getDefault().
getWindowManager().getCurrentWorkspace();
curWs.setToolbarConfigName (newName);
}
} catch (IOException ioe) {
TopManager.getDefault ().notifyException (ioe);
}
}
}
}
});
menu.add (mi);
// menu.add (new JPopupMenu.Separator());
// mi = new JMenuItem ("Test"); // NOI18N
// mi.addActionListener (new ActionListener () {
// public void actionPerformed (ActionEvent e) {
// testPrinting();
// }
// });
// menu.add (mi);
return menu;
} // getContextMenu
// void testPrinting () {
// System.out.println ("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"); // NOI18N
// System.out.println ("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"); // NOI18N
// System.out.println ("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"); // NOI18N
// System.out.println (">>> ToolbarConfiguration [" + super.toString() + "]: " + configName); // NOI18N
// System.out.println (" Toolbar Rows, size = " + toolbarRows.size()); // NOI18N
// for (int i = 0; i < toolbarRows.size(); i++) {
// System.out.print (" # row [" + i + "] = "); // NOI18N
// ((ToolbarRow)toolbarRows.elementAt (i)).testPrinting();
// }
// System.out.println (" Invisible Toolbars, size = " + invisibleToolbars.size()); // NOI18N
// Iterator it = invisibleToolbars.keySet().iterator();
// int i = 0;
// while (it.hasNext()) {
// System.out.print (" # toolbar [" + (i++) + "] = "); // NOI18N
// ((ToolbarConstraints)it.next()).testPrinting();
// }
// System.out.println ("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); // NOI18N
// System.out.println ("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); // NOI18N
// System.out.println ("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); // NOI18N
// }
void moveToolbar2EndHorizontally (ToolbarConstraints tc, int dx) {
if (dx == 0) // no move
return;
if (dx < 0)
tc.moveLeft2End (-dx);
if (dx > 0)
tc.moveRight2End (dx);
}
void moveToolbarHorizontally (ToolbarConstraints tc, int dx) {
if (dx == 0) // no move
return;
if (dx < 0)
tc.moveLeft (-dx);
if (dx > 0)
tc.moveRight (dx);
}
void moveToolbarVertically (ToolbarConstraints tc, int dy) {
if (dy == 0) // no move
return;
if (dy < 0)
moveUp (tc, -dy);
if (dy > 0)
moveDown (tc, dy);
}
void moveUp (ToolbarConstraints tc, int dy) {
if (dy < BASIC_HEIGHT_2)
return;
int rI = tc.rowIndex();
if (draggedToolbar.isAlone()) { // is alone on row(s) -> no new rows
if (rI == 0) // in first row
return;
}
int pos = rI - 1;
tc.destroy();
int plus = 0;
int rowCount = getRowCount();
for (int i = pos; i < pos + tc.getRowCount(); i++) {
getRow (i + plus).addToolbar (tc, tc.getPosition());
if (rowCount != getRowCount()) {
rowCount = getRowCount();
plus++;
}
}
checkToolbarRows();
}
void moveDown (ToolbarConstraints tc, int dy) {
int rI = tc.rowIndex();
int step = BASIC_HEIGHT_2;
if (draggedToolbar.isAlone()) { // is alone on row(s) -> no new rows
if (rI == (toolbarRows.size() - tc.getRowCount())) // in last rows
return;
step = BASIC_HEIGHT_4;
}
if (dy < step)
return;
int pos = rI + 1;
tc.destroy();
for (int i = pos; i < pos + tc.getRowCount(); i++)
getRow (i).addToolbar (tc, tc.getPosition());
checkToolbarRows();
}
// from Toolbar.DnDListener
public void dragToolbar (Toolbar.DnDEvent e) {
if (draggedToolbar == null) {
draggedToolbar = (ToolbarConstraints)allToolbars.get (e.name);
}
switch (e.type) {
case Toolbar.DnDEvent.DND_LINE:
// not implemented yet - it's bug [1]
// not implemented int this version
return; // only Toolbar.DnDEvent.DND_LINE
case Toolbar.DnDEvent.DND_END:
moveToolbar2EndHorizontally (draggedToolbar, e.dx);
break;
case Toolbar.DnDEvent.DND_ONE:
moveToolbarVertically (draggedToolbar, e.dy);
break;
}
if (e.type == Toolbar.DnDEvent.DND_ONE)
moveToolbarHorizontally (draggedToolbar, e.dx);
draggedToolbar.updatePosition();
revalidateWindow();
}
public void dropToolbar (Toolbar.DnDEvent e) {
dragToolbar (e);
reflectChanges();
draggedToolbar = null;
}
// writable classes
// class WritableToolbarConfiguration
class WritableToolbarConfiguration {
/**
* @associates WritableToolbarRow
*/
Vector rows;
public WritableToolbarConfiguration (Vector rs, HashMap iv) {
initRows (rs);
initInvisible (iv);
removeEmptyRows();
}
void initRows (Vector rs) {
rows = new Vector();
Iterator it = rs.iterator();
while (it.hasNext()) {
rows.addElement (new ToolbarRow.WritableToolbarRow ((ToolbarRow)it.next()));
}
}
void initInvisible (HashMap iv) {
Iterator it = iv.keySet().iterator();
ToolbarConstraints tc;
int row;
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
row = ((Integer)iv.get (tc)).intValue();
for (int i = row; i < row + tc.getRowCount(); i++) {
getRow (i).addToolbar (tc);
}
}
}
void removeEmptyRows () {
ToolbarRow.WritableToolbarRow row;
for (int i = rows.size() - 1; i >= 0; i--) {
row = (ToolbarRow.WritableToolbarRow)rows.elementAt (i);
if (row.isEmpty())
rows.removeElement (row);
}
}
ToolbarRow.WritableToolbarRow getRow (int r) {
try {
return (ToolbarRow.WritableToolbarRow)rows.elementAt (r);
} catch (ArrayIndexOutOfBoundsException e) {
rows.addElement (new ToolbarRow.WritableToolbarRow ());
return getRow (r);
}
}
public String toString () {
StringBuffer sb = new StringBuffer();
sb.append ("<").append (TAG_CONFIG).append (">\n"); // NOI18N
Iterator it = rows.iterator();
while (it.hasNext()) {
sb.append (it.next().toString());
}
sb.append ("</").append (TAG_CONFIG).append (">\n"); // NOI18N
return sb.toString();
}
} // end of class WritableToolbarConfiguration
} // end of class Configuration
/*
* Log
* 16 Gandalf 1.15 3/11/00 Martin Ryzl menufix [by E.Adams,
* I.Formanek]
* 15 Gandalf 1.14 1/20/00 Libor Kramolis
* 14 Gandalf 1.13 1/20/00 Libor Kramolis
* 13 Gandalf 1.12 1/19/00 Libor Kramolis
* 12 Gandalf 1.11 1/16/00 Libor Kramolis
* 11 Gandalf 1.10 1/16/00 Libor Kramolis
* 10 Gandalf 1.9 1/13/00 David Simonek localization
* 9 Gandalf 1.8 12/13/99 Libor Kramolis
* 8 Gandalf 1.7 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 7 Gandalf 1.6 9/30/99 Libor Kramolis
* 6 Gandalf 1.5 9/29/99 Libor Kramolis
* 5 Gandalf 1.4 8/16/99 Ian Formanek Fixed 100% CPU problem
* (with each toolbar switch some Vector doubled in size), hopefully
* correctly
* 4 Gandalf 1.3 8/3/99 Libor Kramolis
* 3 Gandalf 1.2 8/3/99 Libor Kramolis
* 2 Gandalf 1.1 7/30/99 Libor Kramolis
* 1 Gandalf 1.0 7/11/99 David Simonek
* $
*/